package cn.openea.perpartner.componet.web.service.impl;

import cn.openea.perpartner.componet.util.SendMsgApi;
import cn.openea.perpartner.componet.util.Tools;
import cn.openea.perpartner.componet.web.entity.InsMsg;
import cn.openea.perpartner.componet.web.entity.UserUnion;
import cn.openea.perpartner.componet.web.mapper.UserUnionMapper;
import cn.openea.perpartner.componet.web.service.ISendMsgService;
import cn.openea.perpartner.componet.web.service.ITemplateMsgService;
import cn.openea.perpartner.componet.web.vo.R;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
 * @codeDesc: 从公众号发送消息到个人的接口实现类
 *  包含发送：普通文本消息、模板消息
 * @author: Mr.Yun
 * @QQ: 2034374624
 * @version: V1.0
 * @Created: 2021/04/29 19:04
 */
@Service
public class ISendMsgServiceImpl implements ISendMsgService {

    @Value("${meily.sendmsg.serverName}")
    private String serverName;
    @Value("${meily.sendmsg.unifiedURI}")
    private String unifiedURI;
    @Value("${meily.sendmsg.onlyWhiteUser}")
    private boolean onlyWhiteUser;

    @Autowired
    private SendMsgApi sendApi;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    UserUnionMapper userUnionMapper;

    @Autowired
    ITemplateMsgService iTemplateMsgService;

    @Override
    public R sendTextMsg(String toWxOpenid, String textmsg) {
        // 组装需要发送的消息
        JSONObject msgobj = new JSONObject();
        msgobj.put("touser", toWxOpenid);
        msgobj.put("msgtype", "text");
        JSONObject textobj = new JSONObject();
        textobj.put("content", textmsg);
        msgobj.put("text", textobj);
        return sendApi.sendMsg(msgobj, "text");
    }

    @Override
    public R sendTemplateMsg(InsMsg msg) {
        // 先取到消息需要发送的用户对象
        if(msg == null || Tools.isBlank(msg.getUserid())){
            return R.error("发送目标对象是空的或无值");
        }
        String userid = msg.getUserid().trim();

        // 先给消息一个id
        if(null == msg.getId()){
            msg.setId(Tools.getNewUnid());
        }

        //redisTemplate.opsForValue().set("componet.whiteUsers", userid + "1," + userid + 2);

        // 查询该用户对应的公众号openid，对用户核心表 sys_user_union 中的字段 myopenid，在之里使用redis缓存加速、
        Map<String, String> umap = (Map<String, String>)redisTemplate.opsForValue().get("componet.umap");
        if(umap == null || umap.isEmpty()){
            // 进入到这里表示redis中还没有记录，需要重新初始化记录
            umap = initUserMap();
        }
        // 进入到这里表示从redis中没有查到对应的记录，此时需要到DB中去找一下用户信息
        if(Tools.isBlank(umap.get(userid))){
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("userid", userid);
            UserUnion userUnion = userUnionMapper.selectOne(queryWrapper);
            if(userUnion != null && Tools.isNotBlank(userUnion.getMyopenid())){
                // 到这里表示从db中找到了一个记录，但这个记录在redis中不存在的，此时需要删除redis中相关的key以便下次能拿到最新的数据
                redisTemplate.delete("componet.umap");
                umap.put(userid, userUnion.getMyopenid());
            }
        }
        String toWxOpenid = umap.get(userid);
        if(Tools.isBlank(toWxOpenid) || toWxOpenid.length() < 20){
            R r = R.error("在用户记录中未匹配到接收者的身份");
            saveMsg(r, msg);
            return r;
        }

        toWxOpenid = toWxOpenid.trim().replace("\\n", "");
        // 判断消息是否需要发送
        if(!"S".equalsIgnoreCase(msg.getMsgstatus())){
            R r = R.ok();
            saveMsg(r, msg);
            return r;
        }

        // 判断消息是否开启了仅对白名单发送
        if(onlyWhiteUser){
            // 从redis中获取白名单，如果白名单中有记录，才发送消息，如果无记录则不发送消息
            String whiteUsers = (String) redisTemplate.opsForValue().get("componet.whiteUsers");
            if(Tools.isBlank(whiteUsers) || !("," + whiteUsers + ",").contains("," + userid + ",")){
                // 如果有白名单中没有找到发送者的userid，则消息不再发送，仅保存
                R r = R.ok();
                saveMsg(r, msg);
                return r;
            }
        }

        // 到了这一步，表示基本验证已经通过，可以进行下一步发送消息了
        R r = sendTemplateMsg(toWxOpenid, msg);
        saveMsg(r, msg);
        return r;
    }

    @Override
    public R sendTemplateMsg(String toWxOpenid, InsMsg msg) {
        // 在这个方法中进行组装参数

        // 需要发送的模板id
        String template_id = msg.getTemplateid();
        // 模板跳转链接
        String url = msg.getUrl();

        // 所需跳转到的小程序信息
        JSONObject miniappdata = new JSONObject();
        if(Tools.isNotBlank(msg.getMiniappid()) && Tools.isNotBlank(msg.getPagepath())){
            miniappdata.put("appid", msg.getMiniappid());

            // 20220214 Add 这里地址不为空时，用于跳转到统一通知调用地址，这里是依据消息应用配置 unifiedURI 值判断的
            String pagepath = msg.getPagepath();
            if(Tools.isNotBlank(unifiedURI)){
                pagepath = unifiedURI + msg.getId();
            }
            pagepath = Tools.decode(pagepath);
            // 20220214 Add 这里地址不为空时，用于跳转到统一通知调用地址，这里是依据消息应用配置 unifiedURI 值判断的

            // 实际地址的参数，官方文档写的pagepath可能不起作用
            miniappdata.put("path", pagepath);
            // 微信官方文档写的内容，实际可能不起作用，这里为能两个都写上，否则会出 invalid weapp pagepath rid
            miniappdata.put("pagepath", pagepath);
        }

        // 消息的业务主体内容
        JSONObject msgdata = new JSONObject();
        msgdata.put("first", getDataJSON(serverName.replace("PROD", "") + msg.getFirst(), ""));
        msgdata.put("keyword1", getDataJSON(msg.getKeyword1(), ""));
        msgdata.put("keyword2", getDataJSON(msg.getKeyword2(), ""));
        msgdata.put("keyword3", getDataJSON(msg.getKeyword3(), ""));
        msgdata.put("keyword4", getDataJSON(msg.getKeyword4(), ""));
        msgdata.put("keyword5", getDataJSON(msg.getKeyword5(), ""));
        msgdata.put("keyword6", getDataJSON(msg.getKeyword6(), ""));
        msgdata.put("remark", getDataJSON(msg.getRemark(), ""));
        // 执行发送消息
        return sendTemplateMsg(toWxOpenid, template_id, url, miniappdata, msgdata);
    }

    @Override
    public R sendTemplateMsg(String toWxOpenid, String template_id, String url, JSONObject miniappdata, JSONObject msgdata) {
        // 组装需要发送的消息
        JSONObject msgobj = new JSONObject();
        msgobj.put("touser", toWxOpenid);
        msgobj.put("template_id", template_id);
        // 模板跳转链接（海外帐号没有跳转能力）
        if(Tools.isNotBlank(url)){
            msgobj.put("url", url);
        }
        // 跳小程序所需数据，不需跳小程序可不用传该数据，包含appid和pagepath的JSON串
        if(null != miniappdata){
            msgobj.put("miniprogram", miniappdata);
        }
        msgobj.put("data", msgdata);
        return sendApi.sendMsg(msgobj, "template");
    }

    @Override
    public R sendTemplateMsg(String toWxOpenid, String template_id, JSONObject miniappdata, JSONObject msgdata) {
        // 调用重载函数
        return sendTemplateMsg(toWxOpenid, template_id, null, miniappdata, msgdata);
    }

    @Override
    public R sendTemplateMsg(String toWxOpenid, String template_id, String url, JSONObject msgdata) {
        // 调用重载函数
        return sendTemplateMsg(toWxOpenid, template_id, url, null, msgdata);
    }

    @Override
    public R sendTemplateMsg(String toWxOpenid, String template_id, JSONObject msgdata) {
        // 调用重载函数
        return sendTemplateMsg(toWxOpenid, template_id, null, null, msgdata);
    }

    @Scheduled(cron = "${meily.sendmsg.cron}")
    @Override
    public void timedSendMessage() {
        // 先获取前50条未发送过的消息
        List<InsMsg> msgList = iTemplateMsgService.selecSendMsgtTopList();
        msgList.forEach(msg -> {
            this.sendTemplateMsg(msg);
        });
    }

    /**
     * 初始化用户与微信公众号的关联关系
     * @return
     */
    private Map<String, String> initUserMap() {
        HashMap<String, String> umap = new HashMap<>();
        QueryWrapper<UserUnion> queryWrapper = new QueryWrapper();
        queryWrapper.select("userid","myopenid").ne("myopenid", "").or().isNotNull("myopenid");
        List<Map<String, Object>> allrows = userUnionMapper.selectMaps(queryWrapper);
        for (int i = 0; i < allrows.size(); i++) {
            Map<String, Object> rowmap = allrows.get(i);
            String userid = (String) rowmap.get("userid");
            String myopenid = (String) rowmap.get("myopenid");
            umap.put(userid, myopenid);
        }
        if (!umap.isEmpty()){
            // 写入redis缓存中
            redisTemplate.opsForValue().set("componet.umap", umap, 12, TimeUnit.HOURS);
        }
        return umap;
    }

    /**
     * 给各keyword值设置默认的颜色
     * @param value
     * @param color
     * @return
     */
    private JSONObject getDataJSON(String value, String color) {
        if(Tools.isBlank(color)){
            color = "#173177";
        }
        JSONObject object = new JSONObject();
        object.put("value", value);
        object.put("color", color);
        return object;
    }

    /**
     * 保存消息实体对象
     * @param r
     * @param msg
     */
    private void saveMsg(R r, InsMsg msg) {
        try {
            // 补充完成消息表的一些基本信息
            msg.setLoggerinfo(r.getMsg());
            if("S".equalsIgnoreCase(msg.getMsgstatus())){
                msg.setMsgstatus(r.getCode()==200?"Y":"E");
            }
            iTemplateMsgService.saveOrUpdate(msg);
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}
